#include "TerrainFX.h"

TerrainFX::TerrainFX(ID3D11Device* device)
	: AbstractFX(device, L"FX/Terrain.fxo")
{
	InitInputLayout(device);
	InitShaderVariablePointers();
}

TerrainFX::~TerrainFX()
{}

void TerrainFX::InitInputLayout(ID3D11Device* device)
{
	const D3D11_INPUT_ELEMENT_DESC inputLayout[] = 
	{
		{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,  D3D11_INPUT_PER_VERTEX_DATA, 0},
		{"NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
		{"TANGENT",  0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0},
		{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, 36, D3D11_INPUT_PER_VERTEX_DATA, 0},
		{"TEXCOORD", 1, DXGI_FORMAT_R32G32_FLOAT,    0, 44, D3D11_INPUT_PER_VERTEX_DATA, 0}
	};

	CreateInputLayout(device, inputLayout, 5);
}

void TerrainFX::InitShaderVariablePointers()
{
	worldVar         = effect->GetVariableByName("world")->AsMatrix();
	worldInvTransVar = effect->GetVariableByName("worldInvTrans")->AsMatrix();
	worldViewProjVar = effect->GetVariableByName("worldViewProj")->AsMatrix();

	texTransformVar  = effect->GetVariableByName("texTransform")->AsMatrix();
	texTransformDetailVar = effect->GetVariableByName("texTransformDetail")->AsMatrix();

	rtWidthVar  = effect->GetVariableByName("rtWidth")->AsScalar();
	rtHeightVar = effect->GetVariableByName("rtHeight")->AsScalar();

	materialVar        = effect->GetVariableByName("mat");
	eyePosVar          = effect->GetVariableByName("eyePosW")->AsVector();
    direcLightVar	   = effect->GetVariableByName("dLight");
	direcLightCountVar = effect->GetVariableByName("dLightCount")->AsScalar();

	//Tile Forward System
	llbVar   = effect->GetVariableByName("LightListBuffer")->AsShaderResource();
	llibVar  = effect->GetVariableByName("LightListIndexBuffer")->AsShaderResource();
	llsebVar = effect->GetVariableByName("LightListStartEndBuffer")->AsShaderResource();

	//Texture map variable
	texMapVar = effect->GetVariableByName("TextureMap")->AsShaderResource();
	texDetailMapVar = effect->GetVariableByName("DetailMap")->AsShaderResource();
	texNormalMapVar = effect->GetVariableByName("NormalMap")->AsShaderResource();
	texMap1Var = effect->GetVariableByName("TextureMap1")->AsShaderResource();
	texNormalMap1Var = effect->GetVariableByName("NormalMap1")->AsShaderResource();
	texMap2Var = effect->GetVariableByName("TextureMap2")->AsShaderResource();
	texNormalMap2Var = effect->GetVariableByName("NormalMap2")->AsShaderResource();

	//Spec maps
	specMapVar = effect->GetVariableByName("SpecMap")->AsShaderResource();
	specMap1Var = effect->GetVariableByName("SpecMap1")->AsShaderResource();
	specMap2Var = effect->GetVariableByName("SpecMap2")->AsShaderResource();

	//Hemispherical lighting
	hemiColDownVar = effect->GetVariableByName("HemiColDown")->AsVector();
	hemiColRangeVar = effect->GetVariableByName("HemiColRange")->AsVector();
	
	//SSAO
	worldViewVar = effect->GetVariableByName("WorldView")->AsMatrix();
	ssaoMapVar = effect->GetVariableByName("SSAOMap")->AsShaderResource();
	ssaoWorldViewProjTexVar = effect->GetVariableByName("SSAOWorldViewProjTex")->AsMatrix();

	//Shadow map
	shadowMapVar = effect->GetVariableByName("ShadowMap")->AsShaderResource();
	shadowMapViewVar = effect->GetVariableByName("ShadowMapView")->AsMatrix();
	shadowMapProjVar = effect->GetVariableByName("ShadowMapProj")->AsMatrix();
	shadowMapToTexVar = effect->GetVariableByName("ShadowMapToTex")->AsMatrix();

	//Height factor CBuffer
	heightFac1Var = effect->GetVariableByName("HeightFac1")->AsScalar();
	heightFac2Var = effect->GetVariableByName("HeightFac2")->AsScalar();

	//ClipPlane
	clipPlaneVar = effect->GetVariableByName("ClipPlane")->AsVector();

	//POM
	hmVar = effect->GetVariableByName("HeightMap")->AsShaderResource();
	hm1Var = effect->GetVariableByName("HeightMap1")->AsShaderResource();
	hm2Var = effect->GetVariableByName("HeightMap2")->AsShaderResource();

	pomMinSamplesVar = effect->GetVariableByName("MinSamples")->AsScalar();
	pomMaxSamplesVar = effect->GetVariableByName("MaxSamples")->AsScalar();

	pomHeightScaleVar = effect->GetVariableByName("HeightScale")->AsScalar();
	pomHeightScale1Var = effect->GetVariableByName("HeightScale1")->AsScalar();
	pomHeightScale2Var = effect->GetVariableByName("HeightScale2")->AsScalar();

	//Layer maps
	layerMap1Var = effect->GetVariableByName("LayerMap1")->AsShaderResource();

	//Layer textures (eg: road)
	layer1TexVar = effect->GetVariableByName("LayerTextureMap1")->AsShaderResource();
	layer1NormalVar = effect->GetVariableByName("LayerNormalMap1")->AsShaderResource();
	layer1SpecVar = effect->GetVariableByName("LayerSpecMap1")->AsShaderResource();
	layer1HeightVar = effect->GetVariableByName("LayerHeightMap1")->AsShaderResource();
}

void TerrainFX::SetLayerTexData(ID3D11ShaderResourceView* layerMap1, 
		ID3D11ShaderResourceView* layer1Tex, ID3D11ShaderResourceView* layer1Normal, 
		ID3D11ShaderResourceView* layer1Spec, ID3D11ShaderResourceView* layer1Height)
{
	//Set 0th layer data
	layerMap1Var->SetResource(layerMap1);
	layer1TexVar->SetResource(layer1Tex);
	layer1NormalVar->SetResource(layer1Normal);
	layer1SpecVar->SetResource(layer1Spec);
	layer1HeightVar->SetResource(layer1Height);
}

void TerrainFX::SetCBufferPerObject(CXMMATRIX& world, 
		CXMMATRIX& worldInvTrans, CXMMATRIX& worldViewProj, 
		Material& mat, 
		CXMMATRIX& worldView)
{
	worldVar->SetMatrix(reinterpret_cast<const float*>(&world));
	worldInvTransVar->SetMatrix(reinterpret_cast<const float*>(&worldInvTrans));
	worldViewProjVar->SetMatrix(reinterpret_cast<const float*>(&worldViewProj));

	materialVar->SetRawValue(&mat, 0, sizeof(Material));

	worldViewVar->SetMatrix(reinterpret_cast<const float*>(&worldView));
}

void TerrainFX::SetTexTransforms(CXMMATRIX& texTrans, CXMMATRIX& texDetailTrans)
{
	texTransformVar->SetMatrix(reinterpret_cast<const float*>(&texTrans));
	texTransformDetailVar->SetMatrix(reinterpret_cast<const float*>(&texDetailTrans));
}

void TerrainFX::SetRTDimensions(unsigned width, unsigned height)
{
	rtWidthVar->SetInt(width);
	rtHeightVar->SetInt(height);
}

void TerrainFX::SetLightingData(XMFLOAT3& eye, 
	DirectionalLight* dLights, unsigned dLightCount,
	ID3D11ShaderResourceView* lightListIndexBuffer, 
	ID3D11ShaderResourceView* lightListStartEndBuffer)
{
	eyePosVar->SetRawValue(&eye, 0, sizeof(XMFLOAT3));
	
	//Cap Direc Lights to 3.
	if (dLightCount > MAX_DIRECTIONAL_LIGHT_COUNT)
		dLightCount = MAX_DIRECTIONAL_LIGHT_COUNT;
	direcLightVar->SetRawValue(dLights, 0, sizeof(DirectionalLight) * dLightCount);
	direcLightCountVar->SetInt(dLightCount);

	//Update LLIB, LLSEB
	llibVar->SetResource(lightListIndexBuffer);
	llsebVar->SetResource(lightListStartEndBuffer);
}

void TerrainFX::SetLightListBuffer(ID3D11ShaderResourceView* lightListBuffer)
{
	llbVar->SetResource(lightListBuffer);
}

void TerrainFX::SetTextureMap(ID3D11ShaderResourceView* textureMap, 
	ID3D11ShaderResourceView* detailMap, 
	ID3D11ShaderResourceView* normalMap, 
	ID3D11ShaderResourceView* textureMap1,
	ID3D11ShaderResourceView* normalMap1,
	ID3D11ShaderResourceView* textureMap2,
	ID3D11ShaderResourceView* normalMap2, 
	ID3D11ShaderResourceView* pomHM,
	ID3D11ShaderResourceView* pomHM1,
	ID3D11ShaderResourceView* pomHM2,
	ID3D11ShaderResourceView* specMap,
	ID3D11ShaderResourceView* specMap1,
	ID3D11ShaderResourceView* specMap2)
{
	texMapVar->SetResource(textureMap);
	texDetailMapVar->SetResource(detailMap);
	texNormalMapVar->SetResource(normalMap);

	texMap1Var->SetResource(textureMap1);
	texNormalMap1Var->SetResource(normalMap1);
	texMap2Var->SetResource(textureMap2);
	texNormalMap2Var->SetResource(normalMap2);

	//Set POM HM data
	hmVar->SetResource(pomHM);
	hm1Var->SetResource(pomHM1);
	hm2Var->SetResource(pomHM2);

	//Set spec maps
	specMapVar->SetResource(specMap);
	specMap1Var->SetResource(specMap1);
	specMap2Var->SetResource(specMap2);
}

void TerrainFX::SetPOMData(int minSamples, int maxSamples, 
		float heightScale0, float heightScale1, float heightScale2)
{
	pomMinSamplesVar->SetInt(minSamples);
	pomMaxSamplesVar->SetInt(maxSamples);

	pomHeightScaleVar->SetFloat(heightScale0);
	pomHeightScale1Var->SetFloat(heightScale1);
	pomHeightScale2Var->SetFloat(heightScale2);
}

void TerrainFX::SetHemisphericalData(XMFLOAT3 &hemiColDown, XMFLOAT3 &hemiColRange)
{
	hemiColDownVar->SetRawValue(&hemiColDown, 0, sizeof(XMFLOAT3));
	hemiColRangeVar->SetRawValue(&hemiColRange, 0, sizeof(XMFLOAT3));
}

void TerrainFX::SetSSAOData(ID3D11ShaderResourceView* ssaoTex, CXMMATRIX &transform)
{
	ssaoMapVar->SetResource(ssaoTex);
	ssaoWorldViewProjTexVar->SetMatrix(reinterpret_cast<const float*>(&transform));
}

void TerrainFX::SetShadowMap(ID3D11ShaderResourceView* shadowMap)
{
	shadowMapVar->SetResource(shadowMap);
}

void TerrainFX::SetShadowMapMatricies(CXMMATRIX &view, CXMMATRIX &proj, CXMMATRIX &toTex)
{
	shadowMapViewVar->SetMatrix(reinterpret_cast<const float*>(&view));
	shadowMapProjVar->SetMatrix(reinterpret_cast<const float*>(&proj));
	shadowMapToTexVar->SetMatrix(reinterpret_cast<const float*>(&toTex));
}

void TerrainFX::SetHeightBasedPatchValues(float heightFac1, float heightFac2)
{
	heightFac1Var->SetFloat(heightFac1);
	heightFac2Var->SetFloat(heightFac2);
}

void TerrainFX::SetClipPlane(XMFLOAT4& clipPlane)
{
	clipPlaneVar->SetFloatVector(reinterpret_cast<const float*>(&clipPlane));
}